﻿//Contributor: Nicolas Muniere


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.ServiceModel.Activation;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Infrastructure;
using Nop.Core.Plugins;
using Nop.Plugin.Misc.WebServices.Security;
using Nop.Services.Authentication;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Security;
using Nop.Services.Catalog;
using Nop.Services.Media;
using Nop.Core.Domain.Media;
using Nop.Core.Domain.Catalog;
using System.IO;
using Nop.Core.Domain.Shipping;
using Nop.Services.Logging;

namespace Nop.Plugin.Misc.WebServices
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class NopService : INopService
    {
        #region Fields

        private readonly IAddressService _addressService;
        private readonly ICountryService _countryService;
        private readonly IStateProvinceService _stateProvinceService;
        private readonly ICustomerService _customerService;
        private readonly ICustomerRegistrationService _customerRegistrationService;
        private readonly CustomerSettings _customerSettings;
        private readonly IPermissionService _permissionSettings;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly IOrderService _orderService;
        private readonly IAuthenticationService _authenticationService;
        private readonly IWorkContext _workContext;
        private readonly IPluginFinder _pluginFinder;
        private readonly IProductService _productService;
        private readonly IPictureService _pictureService;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ILogger _logger;
        private readonly ICategoryService _categoryService;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;

        #endregion 

        #region Ctor

        string WebPathThumb = @"http://127.0.0.1/content/images/thumbs/";
        string WebPathImg = @"http://127.0.0.1/content/images/";

        /// <summary>
        /// Returns the file extension from mime type.
        /// </summary>
        /// <param name="mimeType">Mime type</param>
        /// <returns>File extension</returns>
        protected virtual string GetFileExtensionFromMimeType(string mimeType)
        {
            if (mimeType == null)
                return null;

            string[] parts = mimeType.Split('/');
            string lastPart = parts[parts.Length - 1];
            switch (lastPart)
            {
                case "pjpeg":
                    lastPart = "jpg";
                    break;
                case "x-png":
                    lastPart = "png";
                    break;
                case "x-icon":
                    lastPart = "ico";
                    break;
            }
            return lastPart;
        }

        public string GetPictureLink(Picture picture)
        {
            if (picture == null)
                return "";
            string lastPart = GetFileExtensionFromMimeType(picture.MimeType);
            string seoFileName = picture.SeoFilename; // = GetPictureSeName(picture.SeoFilename); //just for sure
            string localFilename = string.Format("{0}_0.{1}", picture.Id.ToString("0000000"), lastPart);

            return WebPathImg + localFilename;
        }

        public string GetPictureLink200(Picture picture)
        {
            if (picture == null)
                return "";
            string lastPart = GetFileExtensionFromMimeType(picture.MimeType);
            string seoFileName = picture.SeoFilename; // = GetPictureSeName(picture.SeoFilename); //just for sure
            string localFilename = !String.IsNullOrEmpty(seoFileName) ?
                string.Format("{0}_{1}_200.{2}", picture.Id.ToString("0000000"), seoFileName, lastPart) :
                string.Format("{0}_200.{1}", picture.Id.ToString("0000000"), lastPart);
            return WebPathThumb + localFilename;
        }

        public NopService()
        {
            _addressService = EngineContext.Current.Resolve<IAddressService>();
            _countryService = EngineContext.Current.Resolve<ICountryService>();
            _stateProvinceService = EngineContext.Current.Resolve<IStateProvinceService>();
            _customerService = EngineContext.Current.Resolve<ICustomerService>();
            _customerRegistrationService = EngineContext.Current.Resolve<ICustomerRegistrationService>();
            _customerSettings = EngineContext.Current.Resolve<CustomerSettings>();
            _permissionSettings = EngineContext.Current.Resolve<IPermissionService>();
            _orderProcessingService = EngineContext.Current.Resolve<IOrderProcessingService>();
            _orderService = EngineContext.Current.Resolve<IOrderService>();
            _authenticationService = EngineContext.Current.Resolve<IAuthenticationService>();
            _workContext = EngineContext.Current.Resolve<IWorkContext>();
            _pluginFinder = EngineContext.Current.Resolve<IPluginFinder>();
            _productService = EngineContext.Current.Resolve<IProductService>();
            _pictureService = EngineContext.Current.Resolve<IPictureService>();
            _shoppingCartService = EngineContext.Current.Resolve<IShoppingCartService>();
            _genericAttributeService = EngineContext.Current.Resolve<IGenericAttributeService>();
            _logger = EngineContext.Current.Resolve<ILogger>();
            _categoryService = EngineContext.Current.Resolve<ICategoryService>();
            _orderTotalCalculationService = EngineContext.Current.Resolve<IOrderTotalCalculationService>();
        }

        #endregion 

        #region Utilities

        protected List<int> GetChildCategoryIds(int parentCategoryId, bool showHidden = false)
        {
            var categoriesIds = new List<int>();
            var categories = _categoryService.GetAllCategoriesByParentCategoryId(parentCategoryId, showHidden);
            foreach (var category in categories)
            {
                categoriesIds.Add(category.Id);
                categoriesIds.AddRange(GetChildCategoryIds(category.Id, showHidden));
            }
            return categoriesIds;
        }

        protected void CheckAccess(string usernameOrEmail, string userPassword)
        {
            //check whether web service plugin is installed
            var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName("Misc.WebServices");
            if (pluginDescriptor == null)
                throw new ApplicationException("Web services plugin cannot be loaded");

            if (!_customerRegistrationService.ValidateCustomer(usernameOrEmail, userPassword))
                    throw new ApplicationException("Not allowed");
            
            var customer = _customerSettings.UsernamesEnabled ? _customerService.GetCustomerByUsername(usernameOrEmail) : _customerService.GetCustomerByEmail(usernameOrEmail);

            _workContext.CurrentCustomer = customer;
            _authenticationService.SignIn(customer, true);
         
         
            //valdiate whether we can access this web service
            if (!_permissionSettings.Authorize(WebServicePermissionProvider.AccessWebService))
                throw new ApplicationException("Not allowed to access web service");
        }

        protected List<Order> GetOrderCollection(int[] ordersId)
        {
            var orders = new List<Order>();
            foreach (int id in ordersId)
            {
                orders.Add(_orderService.GetOrderById(id));
            }
            return orders;
        }

        protected Prodotti ConvertProduct(IList<Product> prodNop)
        {
            Prodotti prodotti = new Prodotti();
            prodotti.products = new List<products>();
            foreach (var prod in prodNop)
            {
                foreach (var prodvar in prod.ProductVariants)
                {
                    var elem = new products();
                    elem.name = prod.Name;
                    elem.price = Convert.ToDouble(prodvar.Price);
                    elem.origprice = Convert.ToDouble(prodvar.OldPrice);
                    elem.id = prod.Id.ToString();
                    elem.ship = prodvar.ShippingTime;


                    elem.desc = new Desc();
                    elem.desc.lunga = prod.FullDescription;
                    elem.desc.breve = prod.ShortDescription;

                    string imageUrl = string.Empty;
                    var pictures = _pictureService.GetPicturesByProductId(prod.Id, 1);

                    //always use HTTP when getting image URL
                    if (pictures.Count == 0)
                        continue;
                    
                    imageUrl = GetPictureLink200(pictures[0]);


                    elem.imgs = new Imgs();
                    elem.imgs.main = GetPictureLink(pictures[0]); ;
                    elem.imgs.spotlight = imageUrl;
                    elem.imgs.thumb = imageUrl;

                    elem.groups = new Groups();
                    elem.groups.featured = prod.AppFeatured ?? false;
                    elem.groups.spotlight = prod.AppSpotlight ?? false;
                    //    elem.groups.category = "Orologi";
                    prodotti.products.Add(elem);
                }
            }

            return prodotti;

        }

        #endregion

        #region Util
        public bool Login(string usernameOrEmail, string userPassword)
        {
            return false;
        }
        #endregion
        #region Catalog

        public int ValidateUser(string user, string password)
        {
            return _customerRegistrationService.ValidateCustomer2(user, password);
        }


        public Prodotti GetProductsByCategory(string IDCategory, string PriceMin, string PriceMax, string Brand, string search, string IncludeSubCat, string page)
        {
            string srcString = search;
            if (search == "-1")
                srcString = "";

            // Brand non si usa. si usa search

            bool includeSubCat = false;
            if( IncludeSubCat == "1" )
                includeSubCat = true;

            int IDCat = int.Parse(IDCategory);
            decimal? minPrice = decimal.Parse(PriceMin);
            decimal? maxPrice = decimal.Parse(PriceMax); 
            int Page = int.Parse(page);

            List<int> categoryIds = new List<int>();
            if (IDCat > 0)
            {
                categoryIds.Add(IDCat);
                if (includeSubCat)
                {
                    //include subcategories
                    categoryIds.AddRange(GetChildCategoryIds(IDCat));
                }
            }

            ProductSortingEnum sorting = ProductSortingEnum.CreatedOn;
            if (minPrice > 0 || maxPrice > 0)
                sorting = ProductSortingEnum.PriceAsc;

            if( IDCat == 463 )
                sorting = ProductSortingEnum.CreatedOn;

            IList<int> filterableSpecificationAttributeOptionIds = null;

            _logger.Information("Cerco prodotti in " + categoryIds.Count.ToString());
            _logger.Information("Minprice: " + minPrice.ToString());
            _logger.Information("Maxprice: " + maxPrice.ToString());

            var prodNop = _productService.SearchProducts(categoryIds, 0, null, minPrice > 0 ? minPrice : null, maxPrice > 0 ? maxPrice : null,
                0, srcString, true, false, _workContext.WorkingLanguage.Id, null, sorting, Page, 15,
                true, out filterableSpecificationAttributeOptionIds);
            _logger.Information("Trovati prodotti: " + prodNop.Count.ToString());
            return ConvertProduct(prodNop);
        }

        public Prodotti GetProducts()
        {
       // http://127.0.0.1/content/images/thumbs/13775390_SwatchSs12SecretThoughtWhiteSwatchNewCollectionYCS552G_200.jpeg
            var prodNop = _productService.GetAllProductsDisplayedForVetrinaApp();

            return ConvertProduct(prodNop);
        }
        #endregion

        #region Orders

        public DataSet GetPaymentMethod(string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            var plugins = from p in _pluginFinder.GetPlugins<IPaymentMethod>()
                          select p;

            var dataset = new DataSet();
            var datatable = dataset.Tables.Add("PaymentMethod");
            datatable.Columns.Add("SystemName");
            datatable.Columns.Add("Name");
            foreach (var plugin in plugins)
            {
                datatable.LoadDataRow(new object[] { plugin.PluginDescriptor.SystemName, plugin.PluginDescriptor.FriendlyName }, true);
            }
            return dataset;
        }

        public DataSet ExecuteDataSet(string[] sqlStatements, string usernameOrEmail, string userPassword)
        {
            //uncomment lines below in order to allow execute any SQL
            //CheckAccess(usernameOrEmail, userPassword);

            //if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
            //    throw new ApplicationException("Not allowed to manage orders");

            //var dataset = new DataSet();

            //var dataSettingsManager = new DataSettingsManager();
            //var dataProviderSettings = dataSettingsManager.LoadSettings();
            //using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            //{
            //    foreach (var sqlStatement in sqlStatements)
            //    {
            //        DataTable dt = dataset.Tables.Add();
            //        SqlDataAdapter adapter = new SqlDataAdapter();
            //        adapter.SelectCommand = new SqlCommand(sqlStatement, connection);
            //        adapter.Fill(dt);

            //    }
            //}

            //return dataset;




            return null;
        }
        
        public Object ExecuteScalar(string sqlStatement, string usernameOrEmail, string userPassword)
        {
            //uncomment lines below in order to allow execute any SQL
            //CheckAccess(usernameOrEmail, userPassword);
            //if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
            //    throw new ApplicationException("Not allowed to manage orders");

            //Object result;
            //var dataSettingsManager = new DataSettingsManager();
            //var dataProviderSettings = dataSettingsManager.LoadSettings();
            //using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            //{
            //    SqlCommand cmd = new SqlCommand(sqlStatement, connection);
            //    connection.Open();
            //    result = cmd.ExecuteScalar();

            //}

            //return result;



            return null;
        }
        
        public void ExecuteNonQuery(string sqlStatement, string usernameOrEmail, string userPassword)
        {
            //uncomment lines below in order to allow execute any SQL
            //CheckAccess(usernameOrEmail, userPassword);
            //if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
            //    throw new ApplicationException("Not allowed to manage orders");

            //var dataSettingsManager = new DataSettingsManager();
            //var dataProviderSettings = dataSettingsManager.LoadSettings();
            //using (SqlConnection connection = new SqlConnection(dataProviderSettings.DataConnectionString))
            //{
            //    SqlCommand cmd = new SqlCommand(sqlStatement, connection);
            //    connection.Open();
            //    cmd.ExecuteScalar();
            //}
        }

        public List<OrderError> DeleteOrders(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            var errors = new List<OrderError>();
            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    _orderProcessingService.DeleteOrder(order);
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(ex.Message);
                }
            }
            return errors;
        }

        public EsitoRegistrazione RegisterUser(string nome, string cognome, string indirizzo, string cap, string prov, string citta, string country, string user, string password)
        {
            EsitoRegistrazione esito = new EsitoRegistrazione();

            try
            {
                // TODO: verifica se l'email è stata già inserita. nel qual caso non lo registra ma lo valida solo
                // TODO: logga tutti gli errori

                _logger.Information("init");
                Nop.Core.Domain.Common.Address addr = new Core.Domain.Common.Address();
                addr.Address1 = indirizzo;
                addr.City = citta;
                addr.FirstName = nome;
                addr.LastName = cognome;
                addr.ZipPostalCode = cap;
                addr.Country = _countryService.GetCountryByTwoLetterIsoCode(country);
                addr.StateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(prov);
                addr.Email = user;

                _addressService.InsertAddress(addr);
                _logger.Information("inserito address");

                Customer customer = new Customer();
                customer.ShippingAddress = addr;
                customer.BillingAddress = addr;
                customer.Addresses.Add(addr);

                customer.CreatedOnUtc = DateTime.UtcNow;
                customer.LastActivityDateUtc = DateTime.UtcNow;
                customer.LastLoginDateUtc = DateTime.UtcNow;
               
                _customerService.InsertCustomer(customer);
                CustomerRegistrationRequest req = new CustomerRegistrationRequest(customer, user, user, password, PasswordFormat.Encrypted);
                req.Email = user;
                var res = _customerRegistrationService.RegisterCustomer(req);
                if (!res.Success)
                {
                    esito.esito = -1;
                    if (res.Errors.Count > 0)
                        esito.message = res.Errors[0];

                }
                else
                {

                    esito.iduser = customer.Id;

                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, nome);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, cognome);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress, indirizzo);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.ZipPostalCode, cap);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.City, citta);
                    if (addr.Country != null)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CountryId, addr.Country.Id);
                    if (addr.StateProvince != null)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StateProvinceId, addr.StateProvince.Id);
                }
            }
            catch (Exception ex)
            {
                _logger.Error("APP. Errore registrazione utente " + ex.Message, ex, null);
                esito.esito = -10;
                esito.message = "Si è verificato un errore nel nostro server. Prego contattare l'assistenza clienti";
            }

            return esito;

        }

        public string PostData(string data)
        {
            return data;
        }

        public int PostMessage(string userid, string touserid, string message)
        {
       //     _customerRegistrationService.RegisterCustomer(
            int i = 0;
            i++;
            return i;
        }

        public void ClearCart(string sidCustomer)
        {
            int idCustomer = int.Parse(sidCustomer);

            ClearCart(idCustomer);
        }

        void ClearCart(int idCustomer)
        {
            if( _customerService == null )
                throw new Exception("APP: Customer service null");
            var cust = _customerService.GetCustomerById(idCustomer);
            if(cust == null)
            {
                throw new Exception("APP: User " + idCustomer.ToString() + " non trovato");
            }

            //load and validate customer shopping cart
            IEnumerable<ShoppingCartItem> cart = null;
            //load shopping cart

            if (cust.ShoppingCartItems == null)
                return;
            cart = cust.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart);
            if( cart != null )
            //clear shopping cart
                cart.ToList().ForEach(sci => _shoppingCartService.DeleteShoppingCartItem(sci, false));
        }

        public string AddToCart(List<productscart> prod)
        {
            return "ttyy";
        }

        public confirmorderesponse ConfirmOrder(List<productscart> prodcart)
        {
            confirmorderesponse response = new confirmorderesponse();

            //response.esito = 0;
            //response.idordine = 12345;
            //return response;

            Customer cust = null;
            try
            {
                if( prodcart.Count <= 0 )
                {
                    _logger.Error("APP. ConfirmOrder. Tentato di confermare zero prodotti", null, cust);
                    response.esito = -1;
                    response.message = "Si è verificato un errore del server. Contattare l'assistenza clienti supporto@24carati.com";
                    return response;
                }
                
                string user = prodcart[0].user;
                string pwd = prodcart[0].pwd;
                int idcust = prodcart[0].idcustomer;
                _logger.Information(string.Format("APP: user {0}, pwd {1}, idcust {2}", user, pwd, idcust));
                idcust = _customerRegistrationService.ValidateCustomer2(user, pwd);
                if (idcust <= 0)
                {
                    _logger.Error("APP. ConfirmOrder. User o pwd invalide " + user + " " + pwd, null, cust);
                    response.esito = -1;
                    response.message = "Si è verificato un errore del server. Contattare l'assistenza clienti supporto@24carati.com";
                    return response;
                }
                _logger.Information(string.Format("APP: newIdcust {0}", idcust));
                string pagamento = prodcart[0].pag;

                cust = _customerService.GetCustomerById(idcust); 
                
                ClearCart(idcust);

                foreach (var elem in prodcart)
                {
                    if (!AddToCart(elem.prodid, elem.qty, idcust))
                    {
                        var prod = _productService.GetProductById(elem.prodid);
                        string name = prod != null ? prod.Name : "";
                        _logger.Error("APP. Prodotto " + elem.prodid + " non più esistente", null, cust);
                        response.esito = -1;
                        response.message = "Il prodotto " + name + " non esiste più nel nostro listino. Impossibile confermare l'ordine";
                        return response;
                    }

                    if (!string.IsNullOrEmpty(elem.tel))
                    {
                        cust.ShippingAddress.PhoneNumber = elem.tel;
                    }
                }

                                    //load shopping cart
                var cart = cust.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();               

             //   if( shippingChanged )
              //      _addressService.UpdateAddress(cust.ShippingAddress);

                //subtotal without tax
                decimal subtotalBase = decimal.Zero;
                decimal orderSubTotalDiscountAmount = decimal.Zero;
                Nop.Core.Domain.Discounts.Discount orderSubTotalAppliedDiscount = null;
                decimal subTotalWithoutDiscountBase = decimal.Zero;
                decimal subTotalWithDiscountBase = decimal.Zero;
                _orderTotalCalculationService.GetShoppingCartSubTotal(cart, false,
                    out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount,
                    out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);
                //subtotal with discount
                subtotalBase = subTotalWithDiscountBase;
             


                //       var shippingMethod = (FlatRateShippingAdjustment)newOrderNotification.orderadjustment.shipping.Item;
                var shippingOption = new ShippingOption();
                shippingOption.Name = "Shipping.ByTotal";
                shippingOption.Rate = subtotalBase >= 60M ? 0M : 6.9M;

                ProcessPaymentRequest pay = new ProcessPaymentRequest();
                pay.CustomerId = idcust;

                if (pagamento == "paypal" || pagamento == "cartacredito")
                    pay.PaymentMethodSystemName = "Payments.PayPalStandard";
                else if (pagamento == "contrassegno")
                {
                    pay.PaymentMethodSystemName = "Payments.CashOnDelivery";
                    shippingOption.Rate += 4;
                }
                else if (pagamento == "bonifico")
                    pay.PaymentMethodSystemName = "Payments.PayInStore";


                _genericAttributeService.SaveAttribute(cust, SystemCustomerAttributeNames.LastShippingOption, shippingOption);
              
                var req = _orderProcessingService.PlaceOrder(pay);
                if (req.Success)
                {
                    response.esito = 0;
                    response.idordine = req.PlacedOrder.Id;
                }
                else
                {
                    response.esito = -1;
                    if (req.Errors.Count > 0)
                        response.message = req.Errors[0];
                }
            }
            catch (Exception ex)
            {
                _logger.Error("APP. Errore conferma ordine " + ex.Message, ex, cust);
                response.esito = -10;
                response.message = ex.Message;
            }
            return response;
        }

        public bool AddToCart(int prodid, int quantity, int idcustomer)
        {


            var cust = _customerService.GetCustomerById(idcustomer);
            var prod = _productService.GetProductById(prodid);
            if (prod == null)
                return false;
            var defVariant = prod.ProductVariants.FirstOrDefault();
            if (defVariant == null)
                return false;

            var warnings = _shoppingCartService.AddToCart(cust, defVariant, ShoppingCartType.ShoppingCart, "", 0, quantity, false);
            if (warnings.Count == 0)
                return true;
            else
                return false;
        }

        public void AddToCart(string prodid, string quantity, string idcustomer)
        {
            int idCustomer = int.Parse(idcustomer);
            int prodId = int.Parse(prodid);
            int quant = int.Parse(quantity);

            var cust = _customerService.GetCustomerById(idCustomer);
            var prod = _productService.GetProductById(prodId);
            if(prod == null )
                return;
            var defVariant = prod.ProductVariants.FirstOrDefault();
            if(defVariant == null )
                return;

            _shoppingCartService.AddToCart(cust, defVariant, ShoppingCartType.ShoppingCart, "", 0, quant, false);
        }

        public void AddOrder()
        {
           
        //    ProcessPaymentRequest pay = new ProcessPaymentRequest();
            
        //    _orderProcessingService.PlaceOrder(
        }

        void AddOrderNote(int orderId, string note, bool displayToCustomer)
        {
            try
            {
                var order = _orderService.GetOrderById(orderId);
                order.OrderNotes.Add(new OrderNote()
                {
                    Note = note,
                    DisplayToCustomer = displayToCustomer,
                    CreatedOnUtc = DateTime.UtcNow
                });
                _orderService.UpdateOrder(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }
        
        public void UpdateOrderBillingInfo(int orderId, string firstName, string lastName, string phone, string email, string fax, string company, string address1, string address2,
            string city, string stateProvinceAbbreviation, string countryThreeLetterIsoCode, string postalCode, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            try
            {
                var order = _orderService.GetOrderById(orderId);
                var a = order.BillingAddress;
                a.FirstName = firstName;
                a.LastName = lastName;
                a.PhoneNumber = phone;
                a.Email = email;
                a.FaxNumber = fax;
                a.Company = company;
                a.Address1 = address1;
                a.Address2 = address2;
                a.City = city;
                StateProvince stateProvince = null;
                if (!String.IsNullOrEmpty(stateProvinceAbbreviation))
                    stateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(stateProvinceAbbreviation);
                a.StateProvince = stateProvince;
                Country country = null;
                if (!String.IsNullOrEmpty(countryThreeLetterIsoCode))
                    country = _countryService.GetCountryByThreeLetterIsoCode(countryThreeLetterIsoCode);
                a.Country = country;
                a.ZipPostalCode = postalCode;

                _addressService.UpdateAddress(a);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }
        
        public void UpdateOrderShippingInfo(int orderId, string firstName, string lastName, string phone, string email, string fax, string company, string address1, string address2,
            string city, string stateProvinceAbbreviation, string countryThreeLetterIsoCode, string postalCode, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            try
            {
                var order = _orderService.GetOrderById(orderId);
                var a = order.ShippingAddress;
                a.FirstName = firstName;
                a.LastName = lastName;
                a.PhoneNumber = phone;
                a.Email = email;
                a.FaxNumber = fax;
                a.Company = company;
                a.Address1 = address1;
                a.Address2 = address2;
                a.City = city;
                StateProvince stateProvince = null;
                if (!String.IsNullOrEmpty(stateProvinceAbbreviation))
                    stateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(stateProvinceAbbreviation);
                a.StateProvince = stateProvince;
                Country country = null;
                if (!String.IsNullOrEmpty(countryThreeLetterIsoCode))
                    country = _countryService.GetCountryByThreeLetterIsoCode(countryThreeLetterIsoCode);
                a.Country = country;
                a.ZipPostalCode = postalCode;

                _addressService.UpdateAddress(a);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }
        
        public void SetOrderPaymentPending(int orderId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            try
            {
                Order order = _orderService.GetOrderById(orderId);
                order.PaymentStatus = PaymentStatus.Pending;
                _orderService.UpdateOrder(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }
        
        public bool SetOrderPaymentPaid(int orderId, string transactionId, string usernameOrEmail, string userPassword)
        {
            int user = ValidateUser(usernameOrEmail, userPassword);
            if (user <= 0)
                return false;

            try
            {
                var order = _orderService.GetOrderById(Convert.ToInt32(orderId));
                _orderProcessingService.MarkOrderAsPaid(order);
                AddOrderNote(orderId, "Ordine " + orderId.ToString() + " pagato con PayPal da app. Transazione: " + transactionId, false);
            }
            catch (Exception ex)
            {
                _logger.Error("APP. Impossibile marcare l'ordne " + orderId.ToString() + " come pagato. Transazione: " + transactionId + ". Err: " + ex.Message, null, null);
                return false;
            }
            return true;
        }
        
        public void SetOrderPaymentPaidWithMethod(int orderId, string paymentMethodName, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            try
            {
                var order = _orderService.GetOrderById(orderId);
                order.PaymentMethodSystemName = paymentMethodName;
                _orderService.UpdateOrder(order);
                _orderProcessingService.MarkOrderAsPaid(order);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }
        
        public void SetOrderPaymentRefund(int orderId, bool offline, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            try
            {
                var order = _orderService.GetOrderById(orderId);
                if (offline)
                {
                    _orderProcessingService.RefundOffline(order);
                }
                else
                {
                    var errors = _orderProcessingService.Refund(order);
                    if (errors.Count > 0)
                    {
                        throw new ApplicationException(errors[0]);
                    }

                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }

        }

        
        public List<OrderError> SetOrdersStatusCanceled(int[] ordersId, string usernameOrEmail, string userPassword)
        {
            CheckAccess(usernameOrEmail, userPassword);
            if (!_permissionSettings.Authorize(StandardPermissionProvider.ManageOrders))
                throw new ApplicationException("Not allowed to manage orders");

            var errors = new List<OrderError>();
            foreach (var order in GetOrderCollection(ordersId))
            {
                try
                {
                    _orderProcessingService.CancelOrder(order, true);
                }
                catch (Exception ex)
                {
                    throw new ApplicationException(ex.Message);
                }
            }
            return errors;
        }
        
        #endregion
    }
}
